﻿using System.Collections.Generic;
using System.Reflection;
using UnityEngine;

/// <summary>
/// 可绑定的数据
/// </summary>
/// <typeparam name="T"></typeparam>
public class BindableData<T>
{
    private T m_value;

    public BindableData(T value = default(T))
    {
        m_value = value;
    }

    /// <summary>
    /// 设置数值
    /// </summary>
    /// <param name="value"></param>
    public void SetValue(T value)
    {
        if (!value.Equals(m_value))
        {
            T old = m_value;
            m_value = value;
            NotifyChanged(old, value);
        }
    }

    /// <summary>
    /// 设置数值
    /// </summary>
    /// <returns></returns>
    public T GetValue()
    {
        return m_value;
    }

    public delegate void DataEventHandler(T oldValue, T newValue);
    private DataEventHandler m_onChanged;

    /// <summary>
    /// 绑定改变回调
    /// </summary>
    /// <param name="callback"></param>
    public void Bind(DataEventHandler callback)
    {
        m_onChanged += callback;
    }

    /// <summary>
    /// 解绑数值改变回调
    /// </summary>
    /// <param name="callback"></param>
    public void Unbind(DataEventHandler callback)
    {
        m_onChanged -= callback;
    }

    /// <summary>
    /// 托管绑定回调
    /// </summary>
    /// <param name="obj"></param>
    /// <param name="callback"></param>
    public void BindManaged(GameObject obj, DataEventHandler callback)
    {
        if (obj == null)
        {
            Debug.LogError("绑定错误,obj不能为空...");
            return;
        }
        BindManager bm = obj.GetComponent<BindManager>();
        if (bm == null)
        {
            bm = obj.AddComponent<BindManager>();
        }
        bool success = bm.Bind<T>(this, callback);
        if (success)
        {
            Bind(callback);
        }
    }

    /// <summary>
    /// 通知改变
    /// </summary>
    /// <param name="oldValue"></param>
    /// <param name="newValue"></param>
    private void NotifyChanged(T oldValue, T newValue)
    {
        if (m_onChanged != null)
        {
            m_onChanged(oldValue, newValue);
        }
    }

    public static implicit operator T(BindableData<T> value)
    {
        return value.m_value;
    }

}
internal class ManagedData
{
    public object m_self;
    public MethodInfo m_unbindMethod;
    public object m_callback;
}

internal class BindManager : MonoBehaviour
{
    private List<ManagedData> m_datas;

    private void Awake()
    {
        m_datas = new List<ManagedData>();
    }

    private void OnDestroy()
    {
        //脚本销毁时解绑所有数据回调
        for (int i = 0; i < m_datas.Count; i++)
        {
            ManagedData data = m_datas[i];
            data.m_unbindMethod.Invoke(data.m_self, new object[] { data.m_callback });
        }
        m_datas.Clear();
        m_datas = null;
    }

    /// <summary>
    /// 绑定数据
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="data"></param>
    /// <param name="callback"></param>
    /// <returns></returns>
    public bool Bind<T>(BindableData<T> data, object callback)
    {
        MethodInfo unbindMethod = data.GetType().GetMethod("Unbind");
        if (unbindMethod == null)
        {
            Debug.LogError("找不到Unbind方法...");
            return false;
        }
        else
        {
            ManagedData managedData = new ManagedData();
            managedData.m_self = data;
            managedData.m_unbindMethod = unbindMethod;
            managedData.m_callback = callback;
            m_datas.Add(managedData);
            return true;
        }
    }
}